package cn.edu.dlmu.cogo.framework.web;

import cn.edu.dlmu.cogo.framework.config.JavaConfig;
import cn.edu.dlmu.cogo.framework.config.WebConfig;
import cn.edu.dlmu.cogo.framework.context.CogoClass;
import cn.edu.dlmu.cogo.framework.context.Environment;
import cn.edu.dlmu.cogo.framework.utils.CogoClassUtil;
import cn.hutool.core.lang.Console;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.http.ContentType;
import cn.hutool.http.HttpUtil;
import cn.hutool.http.server.HttpServerRequest;
import cn.hutool.http.server.HttpServerResponse;
import cn.hutool.http.server.SimpleServer;
import cn.hutool.json.JSONUtil;
import com.sun.net.httpserver.Filter;
import com.sun.net.httpserver.HttpExchange;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * @author yixi
 */
public class WebServer {

    private SimpleServer server;

    public void startServer(){
        String startUrl = configServer();
        //使用公用线程池处理服务器监听线程，避免程序阻塞
        ThreadUtil.execute(() -> server.getRawServer().start());
        Console.log("{} [CogoWeb]Web服务启动成功[{}]", Environment.getSystemTime(), startUrl);
    }

    private String configServer(){
        // 获取WebConfig配置
        WebConfig config = JavaConfig.getConfig(WebConfig.class);
        // 根据WebConfig配置创建服务器
        server = HttpUtil.createServer(config.getPort());
        // 添加过滤器
        server.addFilter(new Filter() {
            @Override
            public void doFilter(HttpExchange exchange, Chain chain) throws IOException {
               executeFilter(exchange,chain);
            }

            @Override
            public String description() {
                return "CogoFilter";
            }
        });

        server.setRoot(config.getRoot());
        // 根据映射路径反射调用对应Controller中的方法
        RequestBody requestBody = config.getRequestBody();
        // 将方法与Api请求Action绑定
        requestBody.getMapping().forEach(mapping -> {
            CogoClass cogoClass = requestBody.getClassAndMethod(mapping);
            server.addAction(mapping, (httpServerRequest, httpServerResponse) -> {
                Object result = null;
                try {
                    // 使用参数绑定器进行参数绑定并反射执行方法
                    result = new ParamBinder(cogoClass.getClazz(), cogoClass.getMethod(), httpServerRequest, httpServerResponse).invoke();
                } catch (InvocationTargetException | IllegalAccessException e) {
                    e.printStackTrace();
                }

                if (result instanceof File) {
                    // 对返回值为文件类型的单独处理
                    httpServerResponse.write((File) result);
                }else if (result instanceof String){
                    // 对返回值为String的按HTML格式
                    httpServerResponse.write((String) result,ContentType.TEXT_HTML.toString());
                }else {
                    // 其余返回值类型按JSON格式处理
                    httpServerResponse.write(JSONUtil.toJsonStr(result),ContentType.JSON.toString());
                }
            });
        });
        return "http://127.0.0.1:" + config.getPort() + "/";
    }

    private void executeFilter(HttpExchange exchange, Filter.Chain chain) throws IOException {
        HttpServerRequest request = new HttpServerRequest(exchange);
        HttpServerResponse response = new HttpServerResponse(exchange);

        Set<Class<?>> cogoFilters = CogoClassUtil.getClassesExtendClass(CogoFilter.class);
        Map<Integer, Class<?>> filterMap = new HashMap<>(cogoFilters.size());
        for (Class<?> filter : cogoFilters) {
            int order = ReflectUtil.invoke(ReflectUtil.newInstance(filter), ReflectUtil.getMethodByName(filter, "getOrder"));
            if (order < 0){
                Console.error("{} [CogoFilter]过滤器的优先级不能小于零",Environment.getSystemTime());
                break;
            }
            filterMap.put(order,filter);
        }

        // 标记是否所有过滤器都允许放行
        boolean doFilter = true;

        for (Class<?> filter : filterMap.values()) {
            Console.log("{} [CogoFilter]过滤器开始执行[{}]",Environment.getSystemTime(), filter.getName());
            boolean execute = ReflectUtil.invoke(ReflectUtil.newInstance(filter), ReflectUtil.getMethodByName(filter, "execute"), request, response);
            if (!execute) {
                doFilter = false;
                break;
            }
        }

        // 只有所有过滤器允许放行最后才放行
        if (doFilter){
            chain.doFilter(exchange);
        }
    }
}
